﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace AlgorithmTest
{
    // T_[四个数字排序]_[算法名]
    public class T_0177_FindTheWinner : IAlgorithm
    {
        // 1823. 找出游戏的获胜者

        // 共有 n 名小伙伴一起做游戏。小伙伴们围成一圈，按 顺时针顺序 从 1 到 n 编号。
        // 确切地说，从第 i 名小伙伴顺时针移动一位会到达第 (i+1) 名小伙伴的位置，其中 1 <= i < n ，从第 n 名小伙伴顺时针移动一位会回到第 1 名小伙伴的位置。

        // 游戏遵循如下规则：
        //  从第 1 名小伙伴所在位置 开始 。
        //  沿着顺时针方向数 k 名小伙伴，计数时需要 包含 起始时的那位小伙伴。逐个绕圈进行计数，一些小伙伴可能会被数过不止一次。
        //  你数到的最后一名小伙伴需要离开圈子，并视作输掉游戏。
        //  如果圈子中仍然有不止一名小伙伴，从刚刚输掉的小伙伴的 顺时针下一位 小伙伴 开始，回到步骤 2 继续执行。
        //  否则，圈子中最后一名小伙伴赢得游戏。
        //  给你参与游戏的小伙伴总数 n ，和一个整数 k ，返回游戏的获胜者。

        // 提示：
        //  1 <= k <= n <= 500

        public void Test()
        {
            // 算法参数定义
            int n = 5, k = 2;
            // 算法执行与打印
            Console.WriteLine(FindTheWinner(n, k));
        }

        // 算法
        // 模拟....
        public int FindTheWinner(int n, int k)
        {
            var queue = new Queue<int>();
            for (int i = 1; i <= n; i++)
                queue.Enqueue(i);
            while (queue.Count > 1)
            {
                for (int i = 1; i < k; i++)
                    queue.Enqueue(queue.Dequeue());
                queue.Dequeue();
            }
            return queue.Dequeue();
        }
        // 数学+迭代
        // 以下用 f(n, k)f(n, k) 表示 nn 名小伙伴做游戏，每一轮离开圈子的小伙伴的计数为 kk 时的获胜者编号。
        // 当 n = 1 时，圈子中只有一名小伙伴，该小伙伴即为获胜者，因此 f(1, k) = 1
        // 当 n > 1 时，将有一名小伙伴离开圈子，圈子中剩下 n - 1名小伙伴。圈子中的第 k'名小伙伴离开圈子，k'满足 1 ≤ k' ≤ n且 k - k'是 n 的倍数。
        // 由于 1 ≤ k' ≤ n，因此0 ≤ k'-1 ≤ n - 1。又由于 k - k是 n 的倍数等价于(k - 1) - (k' - 1) 是 n 的倍数，
        // 因此 k' - 1 = (k - 1) % n，k' = (k - 1)% n + 1。
        // 当圈子中剩下n - 1名小伙伴时，可以递归地计算 f(n - 1, k)，得到剩下的 n - 1名小伙伴中的获胜者。令 x = f(n - 1, k)。
        // 由于在第 k'名小伙伴离开圈子之后，圈子中剩下的 n - 1名小伙伴从第 k' + 1名小伙伴开始计数，
        // 获胜者编号是从第 k' + 1名小伙伴开始的第x名小伙伴，因此当圈子中有 nn 名小伙伴时，
        // 获胜者编号是 f(n, k) = (k'%n + x - 1) % n + 1 = (k + x - 1) % n + 1。
        // 将 x = f(n - 1, k)代入上述关系，可得：f(n, k) = (k + f(n - 1, k) - 1) % n + 1。
        public int FindTheWinner1(int n, int k)
        {
            if (n == 1)
                return 1;
            return (k + FindTheWinner1(n - 1, k) - 1) % n + 1;
        }
        public int FindTheWinner2(int n, int k)
        {
            int winner = 1;
            for (int i = 2; i <= n; i++)
                winner = (k + winner - 1) % i + 1;
            return winner;
        }
    }
}
